package com.sfaug;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;

public class PongView extends SurfaceView implements SurfaceHolder.Callback {
	
	/** The Thread that handles the animation */
	private PongThread mThread;
	
	/** Text view used to display updated information for users*/
	private TextView mTextView;
    
	/** Handle to the application context, used to e.g. fetch Drawables. */
	private Context mContext;
	
		
	public PongView(Context context) {
		super(context);
        // register our interest in hearing about changes to our surface
        getHolder().addCallback(this);

        // create thread only; it's started in surfaceCreated()
        mThread = new PongThread (this, context, new Handler() {
            @Override
            public void handleMessage(Message m) {
                mTextView.setVisibility(m.getData().getInt("viz"));
                mTextView.setText(m.getData().getString("text"));
            }
        });
        
        //make sure we get key events
        setFocusable(true); 
	}
	
	public PongView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // register our interest in hearing about changes to our surface
        getHolder().addCallback(this);

        // create thread only; it's started in surfaceCreated()
        mThread = new PongThread (this, context, new Handler() {
            @Override
            public void handleMessage(Message m) {
                mTextView.setVisibility(m.getData().getInt("viz"));
                mTextView.setText(m.getData().getString("text"));
            }
        });
        
        //make sure we get key events
        setFocusable(true); 
	}

	/*
     * Callback invoked when the Surface has been created and is ready to be
     * used.
     */
	public void surfaceCreated(SurfaceHolder holder) {
	    // start the thread here so that we don't busy-wait in run()
        // waiting for the surface to be created
        mThread.setRunning(true);
        mThread.start();
		
	}

    /*
     * Callback invoked when the Surface has been destroyed and must no longer
     * be touched. WARNING: after this method returns, the Surface/Canvas must
     * never be touched again!
     */
	public void surfaceDestroyed(SurfaceHolder holder) {
        // we have to tell thread to shut down & wait for it to finish, or else
        // it might touch the Surface after we return and explode
        boolean retry = true;
        mThread.setRunning(false);
        while (retry) {
            try {
                mThread.join();
                retry = false;
            } catch (InterruptedException e) {
            }
        }
		
	}
	
	public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
	}


	/**
	 * @return the mThread
	 */
	public PongThread getThread() {
		return mThread;
	}

	
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return mThread.onTouchEvent(event);
	}

	/**
	 * @param mTextView the mTextView to set
	 */
	public void setTextView(TextView mTextView) {
		this.mTextView = mTextView;
	}

	/**
	 * @return the mTextView
	 */
	public TextView getTextView() {
		return mTextView;
	}
	
	class PongThread extends Thread{
		
        /*
         * State-tracking constants
         */
		public static final int STATE_READY = 1;
		public static final int STATE_RUNNING = 2;
		public static final int STATE_LOSE = 3;
        public static final int STATE_WIN = 4;

        
		/** Handle to the surface manager we interact with */
		private SurfaceHolder mSurfaceHolder;
		
		/** Handle to update main UI - specifically the TextView */
		private Handler mHandler;
		
        /** Indicate whether the surface has been created & is ready to draw */
        private boolean mRun = false;
        
        /** Handle for main pong view*/
        private PongView mPongView;

        
        /** Object represents player1's pong*/
        private Graphic mP1pong;
        
        /** Object which represents player2's pong*/
    	private Graphic mP2pong;
    	
    	/** Object which represents ball */
    	private Graphic mBall;
    	
    	/** State of the game, READY, RUNNNING, LOSE, WIN */
    	private int mGameState;

		
		public PongThread(PongView pongView, Context context,
                Handler handler) {
            // get handles to some important objects
			mPongView = pongView;
            mSurfaceHolder = pongView.getHolder();
            mHandler = handler;
            mContext = context;
            
		}
		
		public void doStart(){
			synchronized(mSurfaceHolder){
				// initialize objects
				Bitmap brick = (Bitmap)BitmapFactory.decodeResource(getResources(), R.drawable.brick);
				mP1pong = new Graphic(brick);
				mP2pong = new Graphic(brick);
				mBall = new Graphic((Bitmap)BitmapFactory.decodeResource(getResources(), R.drawable.ball));
				setStartingSpot(true);
				mGameState = STATE_READY;
			}
		}
		
		private void setStartingSpot(boolean pong1hasBall)
		{
			//pong can only move from side to side
			mP1pong.getSpeed().setY(0);
			mP1pong.getSpeed().setX(0);
			//player1 is on top
			mP1pong.getCoordinates().setY(0);
			//player1 is center
			mP1pong.getCoordinates().setX((mPongView.getWidth() / 2) - mP1pong.getBitmap().getWidth() / 2);
			
			
			//pong can only move from side to side
			mP2pong.getSpeed().setY(0);
			mP2pong.getSpeed().setX(0);
			//player2 is on the bottom
			mP2pong.getCoordinates().setY(mPongView.getHeight() - mP2pong.getBitmap().getHeight());
			//player2 is center
			mP2pong.getCoordinates().setX((mPongView.getWidth() / 2) - mP2pong.getBitmap().getWidth() / 2);
			
			mBall.getSpeed().setX(0);
			mBall.getSpeed().setY(0);
			if(pong1hasBall){
				mBall.getCoordinates().setX(mP1pong.getCoordinates().getX() + mP1pong.getBitmap().getWidth() / 2);
				mBall.getCoordinates().setY(mP1pong.getCoordinates().getY() + mP1pong.getBitmap().getHeight());
			}
			else{
				mBall.getCoordinates().setX(mP2pong.getCoordinates().getX() + mP2pong.getBitmap().getWidth() / 2);
				mBall.getCoordinates().setY(mP2pong.getCoordinates().getY() + mP2pong.getBitmap().getHeight());				
			}
		
		}
		
		private void updatePhysics(){
			Coordinates coord;
			Speed speed;
			
			//TODO need to redo, sloppy
			//player 1 pong
			coord = mP1pong.getCoordinates();
			speed = mP1pong.getSpeed();

			//direction only side to side
			coord.setX(coord.getX() + speed.getX());
						
			//border for x
			if(coord.getX() < 0){
				speed.setX(-speed.getX());
				coord.setX(-coord.getX());
			} else if(coord.getX() + mP1pong.getBitmap().getWidth() > getWidth()){
				speed.setX(-speed.getX());
				int a = coord.getX();
				int b = mPongView.getWidth() ;
				int c = mP1pong.getBitmap().getWidth();
				int z = a +b;
				int y = a + c;
				int x = z -y;
				coord.setX(x);
			}

		
			//TODO need to redo, sloppy
			//player 2 pong
			coord = mP2pong.getCoordinates();
			speed = mP2pong.getSpeed();

			//direction only side to side
			coord.setX(coord.getX() + speed.getX());
			
			//border for x
			if(coord.getX() < 0){
				speed.setX(-speed.getX());
				coord.setX(-coord.getX());
			} else if(coord.getX() + mP2pong.getBitmap().getWidth() > getWidth()){
				speed.setX(-speed.getX());
				int a = coord.getX();
				int b = mPongView.getWidth() ;
				int c = mP2pong.getBitmap().getWidth();
				int z = a +b;
				int y = a + c;
				int x = z -y;
				coord.setX(x);
			}
			
			//TODO need to redo, slppy
			//ball
			coord = mBall.getCoordinates();
			speed = mBall.getSpeed();
			
			//direction only side to side
			coord.setX(coord.getX() + speed.getX());
			coord.setY(coord.getY() + speed.getY());
			
			//border for x
			if(coord.getX() < 0){
				speed.setX(-speed.getX());
				coord.setX(-coord.getX());
			} else if(coord.getX() + mBall.getBitmap().getWidth() > getWidth()){
				speed.setX(-speed.getX());
				int a = coord.getX();
				int b = mPongView.getWidth() ;
				int c = mBall.getBitmap().getWidth();
				int z = a +b;
				int y = a + c;
				int x = z -y;
				coord.setX(x);
			}
			
			//border for y
			if(coord.getY() < 0){
				speed.setY(-speed.getY());
				coord.setY(-coord.getY());
			}else if(coord.getY() + mBall.getBitmap().getHeight() > getHeight()){
				speed.setY(-speed.getY());
				coord.setY(coord.getY() + getHeight() - (coord.getY() + mBall.getBitmap().getHeight()));
			}


		}
		
		private boolean checkCollision(Graphic playerOnePong,Graphic playerTwoPong, Graphic ball){
			return false;
		}
		
		private boolean checkForWinners(){
			//TODO: update handler
			return false;
		}
		
		private void onDraw(Canvas canvas) {
            // Color the canvas -  Operations on the Canvas accumulate
            // so this is like clearing the screen.
            canvas.drawColor(Color.GREEN);
            
            //TODO: clean this up
			if(mThread.mP1pong != null)
				canvas.drawBitmap(mThread.mP1pong.getBitmap(), mThread.mP1pong.getCoordinates().getX(), mThread.mP1pong.getCoordinates().getY(), null);
			if(mThread.mP2pong != null)
				canvas.drawBitmap(mThread.mP2pong.getBitmap(), mThread.mP2pong.getCoordinates().getX(), mThread.mP2pong.getCoordinates().getY(), null);
			if(mThread.mBall != null)
				canvas.drawBitmap(mThread.mBall.getBitmap(), mThread.mBall.getCoordinates().getX(), mThread.mBall.getCoordinates().getY(), null);
	        
		}
		
		boolean onTouchEvent(MotionEvent event) {
	    	synchronized(getHolder()){
	    		if(mThread.getGameState() == PongThread.STATE_READY){
	    			// start ball
	    			mThread.mBall.getSpeed().setX(1);
	    			mThread.mBall.getSpeed().setY(1);
	    			
	    			//TODO: for now just start moving pongs left to right
	    			mThread.mP1pong.getSpeed().setX(1);
	    			mThread.mP2pong.getSpeed().setX(1);
	    			mThread.setGameState(PongThread.STATE_RUNNING);
	    		}
	    	}
	    	return true;
		}
		
		
		public void run(){
			Canvas c ;
			while(mRun){
				c = null;
				try{
					c = mPongView.getHolder().lockCanvas(null);
					synchronized(mPongView.getHolder()){
                        if (mGameState == STATE_RUNNING){
    						updatePhysics();
    						checkForWinners();
                        }
						onDraw(c);
					}
					
				}finally{
					if(c != null){
						mPongView.getHolder().unlockCanvasAndPost(c);
					}
				}
			}

		}
		
	       /**
         * Used to signal the thread whether it should be running or not.
         * Passing true allows the thread to run; passing false will shut it
         * down if it's already running. Calling start() after this was most
         * recently called with false will result in an immediate shutdown.
         * 
         * @param b true to run, false to shut down
         */
        public void setRunning(boolean b) {
            mRun = b;
        }
        
        public int getGameState(){
        	return mGameState;
        }
        
        public void setGameState(int value){
        	mGameState = value;
        }
		
	}

}
